package cn.com.okgo.model;

import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import cn.com.okgo.utils.HttpUtils;
import okhttp3.MediaType;

/**
 * Created by luwenlong on 2017/8/28.
 * 拼接参数
 */

public class HttpParams implements Serializable {

    public static final MediaType MEDIA_TYPE_PLAIN = MediaType.parse( "text/plain;charset=utf-8" );
    public static final MediaType MEDIA_TYPE_JSON = MediaType.parse( "application/json;charset=utf-8" );
    public static final MediaType MEDIA_TYPE_STREAM = MediaType.parse( "application/octet-stream" );

    public static final boolean IS_REPLACE = true;

    /**
     * 普通的键值对参数
     */
    public LinkedHashMap<String, List<String>> urlParamsMap;

    /**
     * 文件的键值对参数
     */
    public LinkedHashMap<String, List<FileWrapper>> fileParamsMap;

    /**
     * 字节的键值对
     */

    public List<Bytes> byteParamsList;

    public HttpParams() {
        init();
    }

    public HttpParams(String key, String value) {
        init();
        put( key, value );
    }

    public HttpParams(String key, File file) {
        init();
        put( key, file );
    }

    private void init() {
        urlParamsMap = new LinkedHashMap<>();
        fileParamsMap = new LinkedHashMap<>();
        byteParamsList = new ArrayList<>();
    }

    public void put(HttpParams params) {
        if (params != null) {
            if (params.urlParamsMap != null && !params.urlParamsMap.isEmpty())
                urlParamsMap.putAll( params.urlParamsMap );
            if (params.fileParamsMap != null && !params.fileParamsMap.isEmpty())
                fileParamsMap.putAll( params.fileParamsMap );
        }
    }

    public void put(Map<String, String> params) {
        if (params == null || params.isEmpty()) return;
        for (Map.Entry<String, String> entry : params.entrySet()) {
            put( entry.getKey(), entry.getValue() );
        }
    }

    public void put(String key, int value) {
        put( key, String.valueOf( value ) );
    }

    public void put(String key, long value) {
        put( key, String.valueOf( value ) );
    }

    public void put(String key, float value) {
        put( key, String.valueOf( value ) );
    }

    public void put(String key, double value) {
        put( key, String.valueOf( value ) );
    }

    public void put(String key, char value) {
        put( key, String.valueOf( value ) );
    }

    public void put(String key, boolean value) {
        put( key, String.valueOf( value ) );
    }

    public void put(String key, String value) {
        if (key != null && value != null) {
            List<String> urlValues = urlParamsMap.get( key );
            if (urlValues == null) {
                urlValues = new ArrayList<>();
                urlParamsMap.put( key, urlValues );
            }
            urlValues.add( value );
        }
    }

    public void putUrlParams(String key, List<String> values) {
        if (key != null && values != null && !values.isEmpty()) {
            for (String value : values) {
                put( key, value );
            }
        }
    }

    public void put(String key, File file) {
        put( key, file, file.getName() );
    }

    public void put(String key, File file, String fileName) {
        put( key, file, fileName, HttpUtils.guessMimeType( fileName ) );
    }

    public void put(String key, FileWrapper fileWrapper) {
        if (key != null && fileWrapper != null) {
            put( key, fileWrapper.file, fileWrapper.fileName, fileWrapper.contentType );
        }
    }

    public void put(String key, File file, String fileName, MediaType contentType) {
        if (key != null) {
            List<FileWrapper> fileWrappers = fileParamsMap.get( key );
            if (fileWrappers == null) {
                fileWrappers = new ArrayList<>();
                fileParamsMap.put( key, fileWrappers );
            }
            fileWrappers.add( new FileWrapper( file, fileName, contentType ) );
        }
    }

    public void putFileParams(String key, List<File> files) {
        if (key != null && files != null && !files.isEmpty()) {
            for (File file : files) {
                put( key, file );
            }
        }
    }

    public void putFileParams(Map<String, File> map) {
        if (null != map && map.size() > 0) {
            for (String key : map.keySet()) {
                put( key, map.get( key ) );
            }
        }
    }

    public void putBytesParams(Bytes bytes) {
        byteParamsList.add( bytes );
    }

    public void putBytesParams(List<Bytes> byteParamsList) {
        this.byteParamsList = byteParamsList;
    }

    public void removeUrl(String key) {
        urlParamsMap.remove( key );
    }

    public void removeFile(String key) {
        fileParamsMap.remove( key );
    }

    public void removeBytes(String key) {
        if (!byteParamsList.isEmpty()) {
            for (Bytes bytes : byteParamsList) {
                if (key.equalsIgnoreCase( bytes.key )) {
                    byteParamsList.remove( bytes );
                }
            }
        }
    }

    public void remove(String key) {
        removeUrl( key );
        removeFile( key );
        removeBytes( key );
    }

    public void clear() {
        urlParamsMap.clear();
        fileParamsMap.clear();
        byteParamsList.clear();
    }

    /**
     * 文件类型的包装类
     */
    public static class FileWrapper implements Serializable {

        public File file;
        public String fileName;
        public transient MediaType contentType;
        public long fileSize;

        public FileWrapper(File file, String fileName, MediaType contentType) {
            this.file = file;
            this.fileName = fileName;
            this.contentType = contentType;
            this.fileSize = file.length();
        }

        private void writeObject(ObjectOutputStream out) throws IOException {
            out.defaultWriteObject();
            out.writeObject( contentType.toString() );
        }

        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
            in.defaultReadObject();
            contentType = MediaType.parse( (String) in.readObject() );
        }

        @Override
        public String toString() {
            return "FileWrapper{" + //
                    "file=" + file + //
                    ", fileName=" + fileName + //
                    ", contentType=" + contentType + //
                    ", fileSize=" + fileSize +//
                    "}";
        }
    }

    @Override
    public String toString() {
        StringBuilder result = new StringBuilder();
        for (ConcurrentHashMap.Entry<String, List<String>> entry : urlParamsMap.entrySet()) {
            if (result.length() > 0) result.append( "&" );
            result.append( entry.getKey() ).append( "=" ).append( entry.getValue() );
        }
        for (ConcurrentHashMap.Entry<String, List<FileWrapper>> entry : fileParamsMap.entrySet()) {
            if (result.length() > 0) result.append( "&" );
            result.append( entry.getKey() ).append( "=" ).append( entry.getValue() );
        }
        return result.toString();
    }
}